package gat.api.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.spring5.dialect.SpringStandardDialect;
import org.thymeleaf.standard.serializer.IStandardJavaScriptSerializer;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;


@Configuration
@Slf4j
public class GatWebConfig implements WebMvcConfigurer {

    @Bean
    public MyInterceptor setBean() {
        return new MyInterceptor();
    }


    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/model/accountSecurity").setViewName("accountSecurity");
        registry.addViewController("/model/help").setViewName("help");
        registry.addViewController("/model/setting").setViewName("setting");
        registry.addViewController("/model/feedback").setViewName("feedback");
        registry.addViewController("/model/myOrder").setViewName("myOrder");
        registry.addViewController("/model/mine").setViewName("mine");
        registry.addViewController("/model/finish").setViewName("finish");
        registry.addViewController("/model/cancel").setViewName("cancel");
        registry.addViewController("/model/login").setViewName("login");
        registry.addViewController("/model/search").setViewName("search");
        registry.addViewController("/model/blank").setViewName("blank");
        registry.addViewController("/model/service").setViewName("service");
        registry.addViewController("/model/message").setViewName("message");
        registry.addViewController("/model/aboutUs").setViewName("aboutUs");
        registry.addViewController("/model/reDetails").setViewName("reDetails");
        registry.addViewController("/model/reSureOrder").setViewName("reSureOrder");
        registry.addViewController("/model/inOrder").setViewName("inOrder");
        registry.addViewController("/model/myWallet").setViewName("myWallet");
        registry.addViewController("/model/invit").setViewName("invit");
        registry.addViewController("/model/cooperate").setViewName("cooperate");
        registry.addViewController("/model/getMoney").setViewName("getMoney");
        registry.addViewController("/model/records").setViewName("records");
        registry.addViewController("/model/refund").setViewName("refund");
        registry.addViewController("/model/resetPassword").setViewName("resetPassword");
        registry.addViewController("/model/reWaitPay").setViewName("reWaitPay");
        registry.addViewController("/model/systemNotice").setViewName("systemNotice");
        registry.addViewController("/model/active").setViewName("active");
    }
    /**
     * 注册拦截器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
         * addInterceptor 注册拦截器
         * addPathPatterns 配置拦截规则
         */

        registry.addInterceptor(setBean())
                .addPathPatterns("/**")
                //view

                .excludePathPatterns("/backgroundUser/login")
                // 找回密码
                //静态资源
                .excludePathPatterns("/static/**")

                // swagger
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/swagger")

                .excludePathPatterns("/", "/csrf")

        ;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");

    }


    /**
     * 针对long型特殊处理,long型json序列化为字符串类型
     * @author bazhandao
     * @date 2021-03-30
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(simpleModule());
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(jackson2HttpMessageConverter);
    }

    private SimpleModule simpleModule() {
        /**
         * 序列换成json时,将所有的long变成string
         * 因为js中得数字类型不能包含所有的java long值
         */
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(long[].class, new LongArrayToStringSerializer());
        simpleModule.addSerializer(Long[].class, new JsonSerializer<Long[]>() {
            @Override
            public void serialize(Long[] value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeStartArray();
                for (Long v : value) {
                    if (v == null) {
                        gen.writeNull();
                    } else {
                        gen.writeString(v.toString());
                    }
                }
                gen.writeEndArray();
            }
        });
        simpleModule.addSerializer(BigDecimal.class, new JsonSerializer<BigDecimal>() {
            @Override
            public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                if (value == null) {
                    gen.writeNull();
                } else {
                    gen.writeString(value.toString());
                }
            }
        });
        return simpleModule;
    }

    @Resource
    private TemplateEngine templateEngine;

    @PostConstruct
    private void init() {
        log.info("WebConfi init...");
        // 通过templateEngine获取SpringStandardDialect
        SpringStandardDialect springStandardDialect = CollectionUtils.findValueOfType(templateEngine.getDialects(), SpringStandardDialect.class);
        IStandardJavaScriptSerializer standardJavaScriptSerializer = springStandardDialect.getJavaScriptSerializer();
        // 反射获取 IStandardJavaScriptSerializer
        Field delegateField = ReflectionUtils.findField(standardJavaScriptSerializer.getClass(), "delegate");
        if (delegateField == null) {
            log.warn("WebConfi init, failed set jasonck module, delegeteField is null !!!");
            return;
        }
        ReflectionUtils.makeAccessible(delegateField);
        Object delegate = ReflectionUtils.getField(delegateField, standardJavaScriptSerializer);
        if (delegate == null) {
            log.warn("WebConfi init, failed set jasonck module, delegete is null !!!");
            return;
        }
        // 如果代理类是JacksonStandardJavaScriptSerializer,则获取mapper,设置model
        if (Objects.equals("JacksonStandardJavaScriptSerializer", delegate.getClass().getSimpleName())) {
            Field mapperField = ReflectionUtils.findField(delegate.getClass(), "mapper");
            if (mapperField == null) {
                log.warn("WebConfi init, failed set jackson module, mapperField is null !!!");
                return;
            }
            ReflectionUtils.makeAccessible(mapperField);
            ObjectMapper objectMapper = (ObjectMapper) ReflectionUtils.getField(mapperField, delegate);
            if (objectMapper == null) {
                log.warn("WebConf init, filed set jackson module, mapper is null !!!");
                return;
            }
            // 设置序列化Module,修改long型序列化为字符串
            objectMapper.registerModule(simpleModule());
            log.info("WebConf init 设置jackson序列化long为字符串成功!!!");
        }
    }



}
